﻿' <file>
' <copyright see="prj:///doc/copyright.txt"/>
' <license see="prj:///doc/license.txt"/>
' <owner name="Shinsaku Nakagawa" email="shinsaku@users.sourceforge.jp"/>
' <version>$Revision: 3113 $</version>
' </file>
'直接从ICSharpCode引用的，关于控制输入法的位置和字体
Imports System
Imports System.Drawing
Imports System.Runtime.InteropServices
Imports System.Windows.Forms
Friend Class Ime
    Public Sub New(ByVal hWnd As IntPtr, ByVal font As Font)
        Dim PROCESSOR_ARCHITEW6432 As String = Environment.GetEnvironmentVariable("PROCESSOR_ARCHITEW6432")
        If PROCESSOR_ARCHITEW6432 = "IA64" OrElse PROCESSOR_ARCHITEW6432 = "AMD64" OrElse Environment.OSVersion.Platform = PlatformID.Unix Then
            disableIME = True
        Else
            Me.hIMEWnd = ImmGetDefaultIMEWnd(hWnd)
        End If
        Me.m_hWnd = hWnd
        Me.m_font = font
        SetIMEWindowFont(font)
    End Sub
    Private m_font As Font = Nothing
    Public Property Font() As Font
        Get
            Return m_font
        End Get
        Set(ByVal value As Font)
            If Not value.Equals(m_font) Then
                m_font = value
                lf = Nothing
                SetIMEWindowFont(value)
            End If
        End Set
    End Property

    Public WriteOnly Property HWnd() As IntPtr
        Set(ByVal value As IntPtr)
            If Me.m_hWnd <> value Then
                Me.m_hWnd = value
                If Not disableIME Then
                    Me.hIMEWnd = ImmGetDefaultIMEWnd(value)
                End If
                SetIMEWindowFont(m_font)
            End If
        End Set
    End Property

    <DllImport("imm32.dll")> _
    Private Shared Function ImmGetDefaultIMEWnd(ByVal hWnd As IntPtr) As IntPtr
    End Function

    <DllImport("user32.dll")> _
    Private Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal msg As Integer, ByVal wParam As IntPtr, ByVal lParam As COMPOSITIONFORM) As IntPtr
    End Function
    <DllImport("user32.dll")> _
    Private Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal msg As Integer, ByVal wParam As IntPtr, <[In](), MarshalAs(UnmanagedType.LPStruct)> ByVal lParam As LOGFONT) As IntPtr
    End Function
    '必须吧LayOutKind属性加上去，表示连续的
    <StructLayout(LayoutKind.Sequential)> _
    Private Class COMPOSITIONFORM
        Public dwStyle As Integer = 0
        Public ptCurrentPos As POINT = Nothing
        Public rcArea As RECT = Nothing
    End Class

    <StructLayout(LayoutKind.Sequential)> _
    Private Class POINT
        Public x As Integer = 0
        Public y As Integer = 0
    End Class

    <StructLayout(LayoutKind.Sequential)> _
    Private Class RECT
        Public left As Integer = 0
        Public top As Integer = 0
        Public right As Integer = 0
        Public bottom As Integer = 0
    End Class

    Private Const WM_IME_CONTROL As Integer = &H283

    Private Const IMC_SETCOMPOSITIONWINDOW As Integer = &HC
    Private hIMEWnd As IntPtr
    Private m_hWnd As IntPtr
    Private Const CFS_POINT As Integer = &H2

    <StructLayout(LayoutKind.Sequential)> _
    Private Class LOGFONT
        Public lfHeight As Integer = 0
        Public lfWidth As Integer = 0
        Public lfEscapement As Integer = 0
        Public lfOrientation As Integer = 0
        Public lfWeight As Integer = 0
        Public lfItalic As Byte = 0
        Public lfUnderline As Byte = 0
        Public lfStrikeOut As Byte = 0
        Public lfCharSet As Byte = 0
        Public lfOutPrecision As Byte = 0
        Public lfClipPrecision As Byte = 0
        Public lfQuality As Byte = 0
        Public lfPitchAndFamily As Byte = 0
        <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=32)> _
        Public lfFaceName As String = Nothing
    End Class
    Private Const IMC_SETCOMPOSITIONFONT As Integer = &HA
    Private lf As LOGFONT = Nothing
    Shared disableIME As Boolean

    Private Sub SetIMEWindowFont(ByVal f As Font)
        If disableIME OrElse hIMEWnd = IntPtr.Zero Then
            Exit Sub
        End If

        If lf Is Nothing Then
            lf = New LOGFONT()
            f.ToLogFont(lf)
            ' This is very important! "Font.ToLogFont" Method sets invalid value to LOGFONT.lfFaceName
            lf.lfFaceName = f.Name
        End If

        Try
            SendMessage(hIMEWnd, WM_IME_CONTROL, New IntPtr(IMC_SETCOMPOSITIONFONT), lf)
        Catch ex As AccessViolationException
            Handle(ex)
        End Try
    End Sub

    Public Sub SetIMEWindowLocation(ByVal x As Integer, ByVal y As Integer)
        If disableIME OrElse hIMEWnd = IntPtr.Zero Then
            'Debug.WriteLine("SetIMEWindowLocation Exit Sub" & " hIMEWnd:" & hIMEWnd.ToString & " disableIME:" & disableIME)
            Exit Sub
        End If

        Dim p As New POINT()
        p.x = x
        p.y = y

        Dim lParam As New COMPOSITIONFORM()
        lParam.dwStyle = CFS_POINT
        lParam.ptCurrentPos = p
        lParam.rcArea = New RECT()

        Try
            SendMessage(hIMEWnd, WM_IME_CONTROL, New IntPtr(IMC_SETCOMPOSITIONWINDOW), lParam)
        Catch ex As AccessViolationException
            Handle(ex)
        End Try
    End Sub

    Private Sub Handle(ByVal ex As Exception)
        Console.WriteLine(ex)
        If Not disableIME Then
            disableIME = True
            MessageBox.Show("Error calling IME: " & ex.Message & vbLf & "IME is disabled.", "IME error")
        End If
    End Sub
End Class
